package cc.imos.component.generator;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

/**
 * <pre>
 *     生成实体来
 *
 * Created by asher on 2017/5/12.
 * </pre>
 */
@Slf4j
@Component
public class GenerateEntityComponent {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private String packageName = "cc.imos.entity";
    private String outputDirBasic = "/src/main/java";
    private String outputDir = outputDirBasic + "/" + packageName.replaceAll("\\.", "/");

    private String sql;
    private String database;
    List<Map<String, Object>> tables;


    public String getDatabase() {
        sql = "select database() `database`";
        database = jdbcTemplate.queryForObject(sql, String.class);
        return database;
    }

    public List<Map<String, Object>> getTables() {
        sql = "SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema = ?";
        tables = jdbcTemplate.queryForList(sql, new Object[] { database });
        return tables;
    }

    public void generate() {
        StopWatch watch = new StopWatch();
        watch.start();

        getDatabase();
        getTables();

        for (Map<String, Object> table: tables) {
            List<String> columnNames = Lists.newLinkedList();
            List<String> columnClassNames = Lists.newLinkedList();
            List<String> columnComments = Lists.newLinkedList();

            String tableName = String.valueOf(table.get("TABLE_NAME"));
            String tableComment = String.valueOf(table.get("TABLE_COMMENT"));

            sql = "SELECT * FROM " + tableName + " LIMIT ?";

            SqlRowSet rowSet = jdbcTemplate.queryForRowSet(sql, new Object[]{0});
            SqlRowSetMetaData metaData = rowSet.getMetaData();
            int columnCount = metaData.getColumnCount();

            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnName(i);
                String columnClassName = metaData.getColumnClassName(i);
                if(columnClassName.contains("java.sql.")) {
                    try {
                        columnClassName = Class.forName(columnClassName).getGenericSuperclass().getTypeName();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }

                columnNames.add(columnName);
                columnClassNames.add(columnClassName);
            }

            sql = "SELECT COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?";
            columnComments = jdbcTemplate.queryForList(sql, new Object[]{ tableName, database},  String.class);

            String content = parser(columnNames ,columnClassNames, columnComments, tableName, tableComment);
            writer(content, tableName);

        }
        watch.stop();
        log.debug("本次生成实体类耗时 {} 毫秒！", watch.getTotalTimeMillis());
    }


    private void writer(String content, String tableName){
        try {
            File directory = new File("");
            String canonicalPath = directory.getCanonicalPath();
            String packagePath = canonicalPath + outputDir;
            String outputPathFile = packagePath + "/" + humpBig(tableName) + ".java";

            File _packagePath = new File(packagePath);
            if (!_packagePath.exists()) {
                _packagePath.mkdir();
            }

            FileWriter fw = new FileWriter(outputPathFile);
            PrintWriter pw = new PrintWriter(fw);
            pw.println(content);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能：生成实体类主体代码
     */
    private String parser(List<String> columnNames, List<String> columnClassNames, List<String> columnComments, String tableName, String tableComment) {
        StringBuffer sb = new StringBuffer();
        sb.append("package " + packageName + ";\r\n");
        sb.append("\r\n");

        sb.append("import lombok.Data;\r\n");

        for(String columnClassName : columnClassNames) {
            if(!columnClassName.startsWith("java.lang.")) {
                sb.append("\r\nimport " + columnClassName + ";\r\n");
            }

        }
        sb.append("\r\n");

        //注释部分
        sb.append("/**\r\n");
        sb.append(" * <pre>\r\n");
        sb.append(" * " + tableName + " " + tableComment + " \r\n");
        sb.append(" * asher for generate \r\n");
        sb.append(" * </pre>\r\n");
        sb.append("*/\r\n");
        //实体部分
        sb.append("@Data\r\n");
        sb.append("public class " + humpBig(tableName) + " {\r\n");
        processAllAttrs(sb, columnNames, columnClassNames, columnComments);//属性
        sb.append("\r\n");
        sb.append("}\r\n");

        return sb.toString();
    }

    private String humpBig(String str) {
        str = humpSmall(str);
        char[] ch = str.toCharArray();
        if(ch[0] >= 'a' && ch[0] <= 'z'){
            ch[0] = (char)(ch[0] - 32);
        }
        return new String(ch);
    }

    private String humpSmall(String str) {
        int i = str.indexOf("_");
        str = str.replaceFirst("_", "");
        if(i != -1) {
            char[] ch = str.toCharArray();
            if(ch[i] >= 'a' && ch[i] <= 'z'){
                ch[i] = (char)(ch[i] - 32);
            }
            str = new String(ch);
            return humpSmall(str);
        }
        return str;
    }


    /**
     * 功能：生成所有属性
     */
    private void processAllAttrs(StringBuffer sb, List<String> columnNames, List<String> columnClassNames, List<String> columnComments) {

        for (int i = 0; i < columnNames.size(); i++) {
            String columnClassName[] = columnClassNames.get(i).split("\\.");
            int j = columnClassName.length;
            String columnComment = columnComments.get(i);

            sb.append("\r\n\t/** " + columnComment +  "*/\n");
            sb.append("\tprivate " + columnClassName[j-1] + " " + humpSmall(columnNames.get(i)) + ";\r\n");
        }
    }
}
